See how the linux kernel organization compares to other vendors in security performance
In the Linux kernel, the following vulnerability has been resolved:
drm/amd/display: Fix dangling pointer in CRTC reset function
amdgpudmcrtcresetstate() frees the old state before allocating a new one. If kzalloc() fails, the function returns without updating the state pointer, leaving a dangling pointer to already freed memory.
Fix this by allocating the new state first. On allocation failure, the old state remains untouched and the function safely returns.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
[adjust for movement around current amd-staging-drm-next]
In the Linux kernel, the following vulnerability has been resolved:
wifi: ath11k: fix stride mismatch in macphycapsparse()
Currently, in ath11kwmitlvmacphycapsparse(), kcalloc() sizes the macphycaps buffer as totphyid len, where len is clamped to min(firmwarelen, sizeof(struct wmimacphycapabilities)). The subsequent memcpy() destination advances by sizeof(full struct) per slot via C pointer arithmetic, not by the clamped len. When firmware sends short TLVs, the second and later slots are written past the end of the allocation.
The reader in ath11kpullmacphycapsvcreadyext() also indexes the buffer with full-struct pointer arithmetic, so the allocation must match that stride.
Fix by using kzallocobjs(), which derives the element size from the pointer type, making allocation size and pointer stride provably consistent regardless of what len the firmware provides.
Compile tested only.
In the Linux kernel, the following vulnerability has been resolved:
RDMA/srp: fix heap information leak on a truncated SRPCREDREQ
srprecvdone() passes wc->bytelen to srpprocessrsp(). It passes nothing to srpprocesscredreq() and srpprocessaerreq(), which read fixed-size fields from the receive buffer without checking that those fields were received.
The buffer size is maxtiiulen, which comes from the login response and is not validated. A target that advertises 8 and then sends an 8-byte SRPCREDREQ makes the initiator read req->tag from beyond the end of the buffer. req->tag is copied into the SRPCREDRSP and sent back, so those bytes reach the target. SRPAERREQ behaves the same way and also reads req->lun.
The leak is 8 bytes per response. maxtiiulen also decides which slab cache the buffer comes from. With 8 the buffer is a kmalloc-8 object and the read is entirely outside it:
BUG: KASAN: slab-out-of-bounds in srprecvdone+0x172b/0x1aa0 Read of size 8 at addr ffff888104714da8 by task kworker/u8:3/50 which belongs to the cache kmalloc-8 of size 8 The buggy address is located 0 bytes to the right of allocated 8-byte region [ffff888104714da0, ffff888104714da8)
Without KASAN the returned bytes are whatever is next in the slab. One run returned ".strtab".
rsp->data[3] in srpprocessrsp() has the same problem: only respdatalen is checked before it is read.
Drop a request that is shorter than the structure being parsed, and check bytelen before the tskmgmt read.
dmaengine: dw-edma: Initialize IRQ data before requesting IRQs
In the Linux kernel, the following vulnerability has been resolved:
scsi: qla2xxx: Bound i2c->length in I2C bsg handlers
struct qlai2caccess carries a 16-bit length field alongside a fixed 64-byte buffer:
struct qlai2caccess { uint16t device, offset, option, length; uint8t buffer[0x40]; } packed;
qla2x00writei2c() and qla2x00readi2c() use the user-supplied i2c->length without any bounds check. i2c is overlaid on a 256-byte on-stack buffer and sfp is a 256-byte DMA-pool buffer, so a length up to 65535 overruns both:
- write: memcpy(sfp, i2c->buffer, i2c->length) over-reads the stack and over-writes the sfp heap buffer, and qla2x00writesfp() then DMAs i2c->length bytes out of the 256-byte buffer. - read: qla2x00readsfp() DMAs i2c->length bytes into the 256-byte sfp, then memcpy(i2c->buffer, sfp, i2c->length) overflows the 64-byte buffer inside the on-stack array.
A caller holding CAPSYSRAWIO can use this to corrupt the heap and the kernel stack. Reject requests whose length exceeds the buffer before any copy or DMA transfer in both handlers.
In the Linux kernel, the following vulnerability has been resolved:
scsi: qla2xxx: Hold vport reference in qla24xxreportidacquisition()
In the format 1 path, the virtual port is located on ha->vplist while holding vportslock, but the lock is dropped before vp is used: qlaupdatehostmap() is called and VPIDXACQUIRED/REGISTERFC4NEEDED/ REGISTERFDMINEEDED are set on vp. No reference is taken across that window, so a concurrent qla24xxdeallocatevpid() can tear the vport down and free it, leading to a use-after-free.
Take a vport reference (vrefcount) under vportslock when the matching vp is found, and drop it after the last use of vp. qla24xxdeallocatevpid() waits for vrefcount to reach zero before unlinking and freeing the vport, so the pointer stays valid. This matches the reference idiom already used by the other ha->vplist traversals.
ext4: check dir entry fits before reading the hash trailer in ext4searchdir()
In the Linux kernel, the following vulnerability has been resolved:
fs/ntfs3: validate dirty page table on log replay
Each DIRPAGEENTRY ends in a pagelcns[] array whose length is the on-disk lcnsfollow field. checkrstbl() validates the table bookkeeping but never checks that this array fits in the entry, so a crafted lcnsfollow lets the v0->v1 conversion memmove and later replay passes run off the entry.
Add checkdptable() to reject, right after checkrstbl(), any entry larger than its size claims via structsize() (the same expression used to allocate these entries, so the check is overflow-safe by construction). All consumers can then trust lcnsfollow as the real capacity. This covers every pagelcns[] access whose index is bounded by the entry itself (the conversion memmove, the HotFix store via finddp(), and the self-bounded scan loops). Accesses whose index comes from the log record need a separate bound and are handled in a follow-up patch.
In the Linux kernel, the following vulnerability has been resolved:
ipv4: reject undersized MTUs in ipdofragment()
ipdofragment() subtracts the IPv4 header length from the effective MTU and passes the resulting payload MTU to ipfragnext().
If the effective MTU is smaller than hlen + 8, ipfragnext() rounds the fragment payload length down to zero. The fragmentation state then never makes forward progress: state->left, state->ptr and state->offset stay unchanged while ipdofragment() keeps allocating and transmitting header-only fragments until the softlockup detector fires.
This is reproducible with a route installed using "mtu lock 20", but it is also reproducible without route MTU lock, for example by forwarding a packet to a device whose MTU is 20.
Fix it in ipdofragment() by rejecting mtu < hlen + 8 with -EMSGSIZE, matching the existing IPv6 fragmentation check.
HID: hyperv: validate initial device info bounds
In the Linux kernel, the following vulnerability has been resolved:
scsi: ufs: core: Initialize hba->rpmbs list in ufshcd
Initialize the hba->rpmbs list in ufshcdallochost() to prevent NULL pointer dereference in the device teardown path if ufsrpmbprobe() fails.
In the Linux kernel, the following vulnerability has been resolved:
netfilter: xtnat: reject unsupported target families
xtnat SNAT and DNAT target handlers assume IP-family conntrack state is present and can dereference a NULL pointer when instantiated from an unsupported family through nftcompat. A bridge-family compat rule can therefore trigger a NULL-dereference in nfnatsetupinfo().
Reject non-IP families in xtnatcheckentry() so unsupported targets cannot be installed. Keep NFPROTOINET allowed for valid inet NAT compat users and leave the runtime fast path unchanged.
[ The crash was fixed via 9dbba7e694ec ("netfilter: nftcompat: ebtables emulation must reject non-bridge targets"), so this patch is no longer critical. Nevertheless, NAT is only relevant for ipv4/ipv6, so this extra family check is a good idea in any case. ]
In the Linux kernel, the following vulnerability has been resolved:
ipv4: fix use-after-free in fibnhcupdatemtu()
fibnhcupdatemtu() walks the nexthop exception table under RTNL, but RTNL does not serialize this walk with PMTU exception updates. The walk uses rcudereferenceprotected() with a constant true condition without holding fnhelock.
The following interleaving can therefore occur:
CPU 0 CPU 1 fibnhcupdatemtu() updateorcreatefnhe() load fnhe spinlockbh(&fnhelock) fnheremoveoldest() unlink fnhe kfreercu(fnhe, rcu) <quiescent state> access fnhe after grace period
KASAN reported:
BUG: KASAN: slab-use-after-free in fibnhcupdatemtu+0x3df/0x410 Read of size 8 at addr ffff888107d49000 by task poc/90 Call Trace: fibnhcupdatemtu+0x3df/0x410 fibsyncmtu+0x7a/0xd0 fibnetdevevent+0x229/0x3f0 netifsetmtuext+0x33a/0x570 devsetmtu+0x88/0x120
The same walk updates fnhepmtu and fnhemtulocked. These fields form a pair and other writers serialize them with fnhelock. RCU alone prevents reclamation, but would still allow concurrent writers to leave a mixed pair.
Walk the table under RCU and acquire fnhelock only while updating each exception. RCU keeps the current entry alive while the short critical section serializes its paired PMTU fields. This avoids holding the global lock while scanning all 2048 buckets for every nexthop.
hwmon: (nct6775-core) Prevent access to unsupported weight registers
In the Linux kernel, the following vulnerability has been resolved:
wifi: mt76: mt7925: validate skb length in testmode query
In mt7925tmquery(), the response skb from mt76mcusendandgetmsg() is used in a memcpy without validating its length:
memcpy(evtresp, skb->data + 8, MT7925EVTRSPLEN);
where MT7925EVTRSPLEN is 512. If the firmware returns a response shorter than 520 bytes (8 + 512), this reads beyond the skb data buffer. The over-read data is then returned to userspace via nlaput() in mt7925testmodedump().
Add a length check before the memcpy to ensure the skb contains sufficient data.
In the Linux kernel, the following vulnerability has been resolved:
net: udptunnel: prevent double queueing in udptunnelnicdevicesync
Yue Sun reported a use-after-free and debugobjects warning in udptunnelnicdevicesyncwork() during concurrent device operations.
The workqueue core clears the internal pending bit before invoking the worker. At that point, a concurrent thread can queue the work again. When the already running worker eventually clears the workpending flag to 0, it mistakenly clears the flag for the newly queued instance. udptunnelnicunregister() then observes workpending as 0 and frees the structure while the second work item is still active in the queue, leading to UAF.
Fix this by returning early in udptunnelnicdevicesync() if workpending is already set, preventing redundant work queueing.
In the Linux kernel, the following vulnerability has been resolved:
vduse: Fix race in vdusedevmsgsync and vdusedevreaditer
There is one race case in vdusedevmsgsync and vdusedevreaditer:
vdusedevreaditer(): lock(msglock); dequeuemsg(sendlist); unlock(msglock); vdusedevmsgsync(): waittimeout() finish lock(msglock); check msg->complete is false listdel(msg); <- double listdel() crash!
To fix this case, we shall ensure vdusemsg is on sendlist or recvlist outside the msglock critical section.
In the Linux kernel, the following vulnerability has been resolved:
KVM: s390: vsie: Add missing radixtreepreload() in gaccessshadowfault()
Add missing radixtreepreload() in gaccessshadowfault() to guarantee forward progress. The core of gaccessshadowfault() has been split into gaccessshadowfault() in order to simplify locking.
In the Linux kernel, the following vulnerability has been resolved:
netfilter: nfconntracksip: validate skbdst() before accessing it
tc ingress and openvswitch do not guarantee routing information to be available. These subsystems use the conntrack helper infrastructure, and the SIP helper relies on the skbdst() to be present if sipexternalmedia is set to 1 (which is disabled by default as a module parameter).
This effectively disables the sipexternalmedia toggle for these subsystems without resulting in a crash.
In the Linux kernel, the following vulnerability has been resolved:
sunrpc: wait for in-flight TLS handshake callback when cancel loses race
When waitforcompletioninterruptibletimeout() in svctcphandshake() returns 0 (timeout) or -ERESTARTSYS (signal) and tlshandshakecancel() then returns false, handshakecomplete() has won the cancellation race: it has set HANDSHAKEFREQCOMPLETED and is about to invoke svctcphandshakedone(), but the callback's side effects on xptflags and on svsk->skhandshakedone have not yet committed.
The current code reads xptflags immediately to decide whether the session succeeded. Two races result.
If the callback has executed setbit(XPTTLSSESSION) but not yet clearbit(XPTHANDSHAKE), svctcphandshake() sees a session, enqueues the transport, and returns. svcxprtreceived() then clears XPTBUSY, a worker thread picks the transport up, the dispatcher in svchandlexprt() observes XPTHANDSHAKE still set, and xpohandshake is invoked a second time. That svctcphandshake() calls initcompletion(&svsk->skhandshakedone) while the original callback concurrently calls completeall() on it, corrupting the embedded swaitqueue.
If the callback has set HANDSHAKEFREQCOMPLETED but not yet entered svctcphandshakedone(), svctcphandshake() reads XPTTLSSESSION as clear and tears the connection down even though the handshake is about to succeed.
Wait for the callback to commit before inspecting xptflags. The completion is guaranteed to fire because handshakecomplete() invokes svctcphandshakedone() unconditionally once it has set HANDSHAKEFREQCOMPLETED.
In the Linux kernel, the following vulnerability has been resolved:
net/9p: fix infinite loop in p9clientrpc on fatal signal
When p9clientrpc() is called with type P9TFLUSH and the transport has no peer (e.g. fd transport backed by pipes with no 9p server), a fatal signal causes an infinite loop:
again: err = iowaiteventkillable(req->wq, ...) / SIGKILL wakes the task, returns -ERESTARTSYS /
if (err == -ERESTARTSYS && c->status == Connected && type == P9TFLUSH) { sigpending = 1; clearthreadflag(TIFSIGPENDING); goto again; }
clearthreadflag() clears TIFSIGPENDING before jumping back to iowaiteventkillable(). signalpendingstate() checks TIFSIGPENDING, finds it zero, and the task goes to sleep again. The task can only wake on the next signal delivery that calls signalwakeup() and sets TIFSIGPENDING again. When that happens the loop repeats, clears TIFSIGPENDING, and sleeps again indefinitely.
This is triggered in practice by coredumpwait(): when a thread in a multi-threaded process causes a coredump (e.g. via SIGSYS from Syscall User Dispatch), coredumpwait() sends SIGKILL to all other threads and waits for them to call mmrelease(). If one of those threads is blocked in p9clientrpc() over an fd transport with no peer, it enters the P9TFLUSH loop and never calls mmrelease(), so coredumpwait() stalls forever:
INFO: task syz.0.18:676 blocked for more than 143 seconds. Not tainted 6.12.77+ #1 task:syz.0.18 state:D stack:27600 pid:676 tgid:673 ppid:630 flags:0x00000004 Call Trace: <TASK> contextswitch kernel/sched/core.c:5344 [inline] schedule+0xcb4/0x5d50 kernel/sched/core.c:6724 scheduleloop kernel/sched/core.c:6801 [inline] schedule+0xe5/0x350 kernel/sched/core.c:6816 scheduletimeout+0x253/0x290 kernel/time/timer.c:2593 dowaitforcommon kernel/sched/completion.c:95 [inline] waitforcommon+0x409/0x600 kernel/sched/completion.c:116 waitforcommon kernel/sched/completion.c:127 [inline] waitforcompletionstate+0x1d/0x40 kernel/sched/completion.c:264 coredumpwait fs/coredump.c:448 [inline] docoredump+0x854/0x4350 fs/coredump.c:629 getsignal+0x1425/0x2730 kernel/signal.c:2903 archdosignalorrestart+0x81/0x880 arch/x86/kernel/signal.c:337 exittousermodeloop kernel/entry/common.c:111 [inline] exittousermodeprepare include/linux/entry-common.h:328 [inline] syscallexittousermodework kernel/entry/common.c:207 [inline] syscallexittousermode+0xf9/0x160 kernel/entry/common.c:218 dosyscall64+0x102/0x220 arch/x86/entry/common.c:84 entrySYSCALL64afterhwframe+0x77/0x7f </TASK>
Fix: check fatalsignalpending() before clearing TIFSIGPENDING in the P9TFLUSH retry loop. At that point TIFSIGPENDING is still set, so fatalsignalpending() works correctly. If a fatal signal is pending, jump to recalcsigpending to restore TIFSIGPENDING and return -ERESTARTSYS to the caller.
The same defect is present in stable kernels back to 5.4. On those kernels the infinite loop is broken earlier by a second SIGKILL from the parent process (e.g. killandwait() retrying after a timeout), resulting in a zombie process and a shutdown delay rather than a permanent D-state hang, but the underlying flaw is the same.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
In the Linux kernel, the following vulnerability has been resolved:
net/sched: actct: preserve tcskbcb across defragmentation
tcfcthandlefragments() calls nfcthandlefragments() without saving and restoring skb->cb. The defrag helper clears IPCB/IP6CB, which aliases the tcskbcb/qdiscskbcb control buffer. Fragmented traffic through actct therefore loses qdisc metadata such as pktsegs and can trigger WARNONONCE() in qdiscpktsegs() when paniconwarn is enabled.
Save and restore the full tcskbcb around nfcthandlefragments(), matching the pattern used by ovscthandlefragments().
drm/amdkfd: clamp v9 CRIU control stack checkpoint copy to BO size
ASoC: tas2781: bound firmware description string parsing
In the Linux kernel, the following vulnerability has been resolved:
net: txgbe: fix FDIR filter leak on remove
Perfect FDIR filters can be added while the interface is down and are kept on the software list for later restore. unregisternetdev() only calls ndostop when the device is up, so txgbefdirfilterexit() in txgbeclose() is skipped in that case and the filters are leaked on driver remove. Free the filter list from txgberemove() as well.
In the Linux kernel, the following vulnerability has been resolved:
usb: gadget: function: rndis: add length check for header
Add a length check for the rndis header in rndisrmhdr, to ensure that MessageType, MessageLength, DataOffset, and DataLength fields are present before they are accessed.
In the Linux kernel, the following vulnerability has been resolved:
i2c: tegra: fix pmruntime leak on mutexlock failure
If tegrai2cmutexlock() fails, the function returns without calling pmruntimeput(), leaking the runtime PM reference acquired by the preceding pmruntimegetsync(). This prevents the device from ever entering runtime suspend.
Add the missing pmruntimeput() before returning on lock failure.
In the Linux kernel, the following vulnerability has been resolved:
f2fs: bound iinlinexattrsize for non-inline-xattr inodes
When the flexibleinlinexattr feature is enabled, doreadinode() loads the on-disk iinlinexattrsize unconditionally:
if (f2fssbhasflexibleinlinexattr(sbi)) fi->iinlinexattrsize = le16tocpu(ri->iinlinexattrsize);
but sanitycheckinode() only range-checks it when the inode also has the FIINLINEXATTR flag set. An inode that carries an inline dentry or inline data but not FIINLINEXATTR -- the normal layout for an inline directory -- therefore keeps a fully attacker-controlled iinlinexattrsize from a crafted image.
getinlinexattraddrs() returns that value with no flag gating, so it feeds the inode geometry:
MAXINLINEDATA() = 4 (CURADDRSPERINODE - iinlinexattrsize - 1) NRINLINEDENTRY() = MAXINLINEDATA() BITSPERBYTE / (...) addrsperpage() = CURADDRSPERINODE - iinlinexattrsize
A large iinlinexattrsize drives MAXINLINEDATA() and NRINLINEDENTRY() negative, so makedentryptrinline() sets d->max (int) to a negative value. The inline directory walk then compares an unsigned long bitpos against that negative d->max, which is promoted to a huge unsigned bound, and reads far past the inline area:
while (bitpos < d->max) / fs/f2fs/dir.c / ... testbitle(bitpos, d->bitmap) / d->dentry[bitpos] ...
Mounting a crafted image and reading such a directory triggers an out-of-bounds read in f2fsfilldentries(); the same underflow also corrupts ADDRSPERINODE for regular files.
Validate iinlinexattrsize against MAXINLINEXATTRSIZE whenever the flexibleinlinexattr feature is enabled -- i.e. whenever the value is loaded from disk and consumed -- and keep the lower MININLINEXATTRSIZE bound gated on inodes that actually carry an inline xattr, so legitimate inodes with iinlinexattrsize == 0 are still accepted.
In the Linux kernel, the following vulnerability has been resolved:
ipv6: fix possible UAF in icmpv6rcv()
Caching saddr and daddr before pskbpull() is problematic since skb->head can change.
Remove these temporary variables:
- We only access &ipv6hdr(skb)->saddr and &ipv6hdr(skb)->daddr when netdbgratelimited() is called in the slow path.
- Avoid potential future misuse after pskbpull() call.
In the Linux kernel, the following vulnerability has been resolved:
net: ipv6: fix NOREF dst use in seg6 and rpl lwtunnels
seg6inputcore() and rplinput() call ip6routeinput() which sets a NOREF dst on the skb, then pass it to dstcachesetip6() invoking dsthold() unconditionally. On PREEMPTRT, ksoftirqd is preemptible and a higher-priority task can release the underlying pcpurt between the lookup and the caching through a concurrent FIB lookup on a shared nexthop. Simplified race sequence:
ksoftirqd/X higher-prio task (same CPU X) ----------- -------------------------------- seg6inputcore(,skb)/rplinput(skb) dstcacheget() -> miss ip6routeinput(skb) -> ip6polroute(,skb,flags) [RT6LOOKUPFDSTNOREF in flags] -> FIB lookup resolves fib6nh [nhid=N route] -> rt6makepcpuroute() [creates pcpurt, refcount=1] pcpurt->sernum = fib6sernum [fib6sernum=W] -> cmpxchg(fib6nh.rt6ipcpu, NULL, pcpurt) [slot was empty, store succeeds] -> skbdstsetnoref(skb, dst) [dst is pcpurt, refcount still 1]
rtgenidbumpipv6() -> bumps fib6sernum [fib6sernum from W to Z] ip6routeoutput() -> ip6polroute() -> FIB lookup resolves fib6nh [nhid=N] -> rt6getpcpuroute() pcpurt->sernum != fib6sernum [W <> Z, stale] -> prev = xchg(rt6ipcpu, NULL) -> dstrelease(prev) [prev is pcpurt, refcount 1->0, dead]
dst = skbdst(skb) [dst is the dead pcpurt] dstcachesetip6(dst) -> dsthold() on dead dst -> WARN / use-after-free
For the race to occur, ksoftirqd must be preemptible (PREEMPTRT without PREEMPTRTNEEDSBHLOCK) and a concurrent task must be able to release the pcpurt. Shared nexthop objects provide such a path, as two routes pointing to the same nhid share the same fib6nh and its rt6ipcpu entry.
Fix seg6inputcore() and rplinput() by calling skbdstforce() after ip6routeinput() to force the NOREF dst into a refcounted one before caching. The output path is not affected as ip6routeoutput() already returns a refcounted dst.